/**
Author: Maciej Oczko
Date: November 2011
*/

#include "PoolMemoryManager.h"

PoolMemoryManager::PoolMemoryManager(unsigned p_ElementSize, unsigned p_Capacity) : m_ElementSize(p_ElementSize), m_Capacity(p_Capacity)
{
	assert(m_Capacity > 0 && "Invalid size specified.");
	m_Data = new char[m_Capacity * m_ElementSize];
	m_FreeObjects = new char*[m_Capacity];
	m_Pointers = new char*[m_Capacity];
	assert(m_Data && "Not enough memory to allocate object data.");
	assert(m_FreeObjects && "Not enough memory to allocate pointer stack.");
	FreeAll();
}


PoolMemoryManager::~PoolMemoryManager()
{
	if(m_Data) delete [] m_Data;
	if(m_FreeObjects) delete [] m_FreeObjects;
	if(m_Pointers) delete [] m_Pointers;
}

void PoolMemoryManager::FreeAll()
{
	unsigned index = m_Capacity - 1;
	for(m_FreeCount = 0; m_FreeCount < m_Capacity; m_FreeCount++)
	{
		m_FreeObjects[m_FreeCount] = m_Pointers[m_FreeCount] = &(m_Data[index-- * m_ElementSize]);
	}
}

void * PoolMemoryManager::New()
{
	assert(m_FreeCount && "No free instances available for allocation.");
	return m_FreeObjects[--m_FreeCount];
}

void * PoolMemoryManager::New(unsigned &p_id)
{
	void * ptr = New();
	for(unsigned i = 0; i < m_Capacity; ++i)
	{
		if(m_Pointers[i] == (char*)ptr)
		{
			p_id = i;
		}
	}
	return ptr;
}

void PoolMemoryManager::Delete(void *p_Instance)
{
	assert(BelongsTo(p_Instance) && "An object is not from this memory block.");
	assert((m_FreeCount < m_Capacity) && "You have freed at least one instance more than once." );
	m_FreeObjects[m_FreeCount++] = (char*)p_Instance;
}

bool PoolMemoryManager::Delete(unsigned int p_Id)
{
	assert(p_Id >= 0 && p_Id < m_Capacity && "Invalid index of memory block.");
	if(!(p_Id >= 0 && p_Id < m_Capacity)) return false;
	Delete(m_Pointers[p_Id]);
	return true;
}